package com.gbase8c.dmt.service;

import com.alibaba.datax.core.util.container.ClassLoaderSwapper;
import com.alibaba.datax.core.util.container.CoreConstant;
import com.alibaba.datax.core.util.container.JarLoader;
import com.gbase8c.dmt.common.exception.DataSourceException;
import com.gbase8c.dmt.model.enums.DbType;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;

import javax.sql.DataSource;
import java.io.File;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class DataSourceFactory {

    private static final Lock lock = new ReentrantLock();
    private static final ConcurrentHashMap<String, DataSource> dataSources = new ConcurrentHashMap<>();

    public static void destroy(String id) {
        dataSources.remove(id);
    }

    public static DataSource getDataSource(DataSourceDto dto) {
        DataSource ds;
        if (dto.getId() != null) {
            if (dataSources.containsKey(dto.getId())) {
                ds = dataSources.get(dto.getId());
            } else {
                lock.lock();
                try {
                    if (dataSources.containsKey(dto.getId())) {
                        ds = dataSources.get(dto.getId());
                    } else {
                        ds = dataSource(dto);
                        dataSources.put(dto.getId(), ds);
                    }
                } catch (Exception e) {
                    log.error("创建数据源失败!", e);
                    throw DataSourceException.asDataSourceException("创建数据源失败!", e);
                } finally {
                    lock.unlock();
                }
            }
        } else {
            ds = dataSource(dto);
        }

        return ds;
    }

    /**
     * 将前端传过来的dto转换成 java.sql.DataSource
     */
    private static DataSource dataSource(DataSourceDto dto) {
        HikariDataSource dataSource = new HikariDataSource();
        // todo 开放参数
        String connectionTestQuery = null;
        if (dto.getDbType().equals(DbType.Oracle)) {
            connectionTestQuery = "select 1 from dual";
        }
        if (dto.getDbType().equals(DbType.GBase8c)
                || dto.getDbType().equals(DbType.GBase8s)) {
            connectionTestQuery = "select 1";
        }

        String pluginPath;

        pluginPath = CoreConstant.DATAX_PLUGIN_READER_HOME + File.separator + dto.getDbType().name().toLowerCase() + "reader" + File.separator + "libs";
        File file = new File(pluginPath);
        if (!file.exists()) {
            pluginPath = CoreConstant.DATAX_PLUGIN_WRITER_HOME + File.separator + dto.getDbType().name().toLowerCase() + "writer" + File.separator + "libs";
        }

        JarLoader jarLoader = new JarLoader(new String[]{pluginPath});
        ClassLoaderSwapper classLoaderSwapper = ClassLoaderSwapper.newCurrentThreadClassLoaderSwapper();
        classLoaderSwapper.setCurrentThreadClassLoader(jarLoader);

        dataSource.setUsername(dto.getUsername());
        dataSource.setPassword(dto.getPassword());
        dataSource.setJdbcUrl(dto.getJdbcUrl());
        dataSource.setDriverClassName(dto.getDriverClass());
        dataSource.setMinimumIdle(10);
        dataSource.setMaximumPoolSize(400);
        // todo 这块应该开放参数, 毕竟每个数据库的参数都是不一样的
        if (dto.getDbType().equals(DbType.GBase8c)
                || dto.getDbType().equals(DbType.GBase8s)) {
            // 8分钟
            dataSource.setIdleTimeout(480000);
            // 9分钟
            dataSource.setMaxLifetime(540000);
        }
        dataSource.setConnectionTestQuery(connectionTestQuery);
        return dataSource;
    }

}